#include "types.h"   // 基本数据类型定义
#include "printf.h"  // 函数声明头文件

// 声明外部函数：这些函数在uart.c中实现
extern void uart_putc(char c);   // UART字符输出函数
extern void uart_puts(const char *s); // UART字符串输出函数

// 数字转换函数：将整数转换为指定进制的字符串表示
// 参数：num - 要转换的数字, base - 进制(10或16), sign - 是否处理符号(1处理，0不处理)
static void printint(int num, int base, int sign) {
    char buf[32];      // 转换缓冲区：32个字符足够存储64位整数的字符串表示
    int i = 0;         // 缓冲区写入位置索引
    unsigned int x;     // 无符号数值，用于安全的算术运算

    // 符号处理：如果有符号且为负数，转换为正数处理
    if (sign && num < 0) {
        x = -num;  // 取负值，INT_MIN(-2147483648)取负会溢出，但unsigned可以处理
    } else {
        x = num;   // 正数或无符号数直接使用
    }

    // 进制转换循环：使用除基取余法
    do {
        int digit = x % base;  // 计算当前最低位的数字
        
        // 数字到字符的转换：避免使用字符数组来防止链接器重定位问题
        if (digit < 10) {
            buf[i++] = '0' + digit;  // 数字0-9：'0'的ASCII码加上偏移量
        } else {
            buf[i++] = 'a' + (digit - 10); // 字母a-f：用于十六进制表示
        }
        x /= base;  // 除以基数，移动到更高位
    } while (x != 0);  // 当所有数位都处理完毕时结束

    // 负号处理：如果是有符号负数，在转换后的字符串前添加负号
    if (sign && num < 0) {
        buf[i++] = '-';  // 在缓冲区末尾添加负号（因为后面会逆序输出）
    }

    // 逆序输出：进制转换得到的是从低位到高位的字符，需要反向输出
    while (--i >= 0) {
        uart_putc(buf[i]);  // 从最高位开始输出字符
    }
}

// 字符串输出函数：安全地输出字符串，处理NULL指针情况
static void printstring(const char *str) {
    if (str == 0) {
        // 安全处理：遇到NULL指针时输出"(null)"而不是导致崩溃
        uart_puts("(null)");
        return;
    }
    
    // 遍历字符串直到遇到空终止符('\0')
    const char *p = str;  // 使用指针遍历字符串
    while (*p) {          // 当当前字符不是'\0'时继续循环
        uart_putc(*p);    // 输出当前字符
        p++;              // 移动到下一个字符
    }
}

// 主printf函数：支持可变参数的格式化输出
// 参数：fmt - 格式字符串, ... - 可变参数列表
// 返回值：总是返回0，符合C标准库约定
int printf(const char *fmt, ...) {
    va_list ap;        // 可变参数列表对象
    va_start(ap, fmt); // 初始化可变参数，fmt是最后一个固定参数

    int i;     // 格式字符串的当前索引位置
    char c;    // 当前正在处理的字符
    
    // 遍历格式字符串中的每个字符
    for (i = 0; (c = fmt[i]) != '\0'; i++) {
        if (c != '%') {
            // 普通字符：不是格式符，直接输出到UART
            uart_putc(c);
            continue;  // 继续处理下一个字符
        }
        
        // 遇到'%'字符，进入格式解析模式
        i++;           // 移动到格式字符位置
        c = fmt[i];    // 获取格式字符
        if (c == '\0') break;  // 如果格式字符串意外结束，退出循环
        
        // 根据格式字符选择相应的处理方式
        switch (c) {
            case 'd':  // 有符号十进制整数
                printint(va_arg(ap, int), 10, 1);  // 基数10，处理符号
                break;
            case 'u':  // 无符号十进制整数
                printint(va_arg(ap, int), 10, 0);  // 基数10，不处理符号
                break;
            case 'x':  // 十六进制整数（小写字母）
                printint(va_arg(ap, int), 16, 0);  // 基数16，不处理符号
                break;
            case 'c':  // 单个字符
                // char类型在可变参数中会提升为int类型
                uart_putc((char)va_arg(ap, int));
                break;
            case 's':  // 字符串
                printstring(va_arg(ap, char*));  // 获取字符串指针参数
                break;
            case '%':  // 字面量百分号：输出一个'%'字符
                uart_putc('%');
                break;
            default:   // 未知格式符：恢复性错误处理
                uart_putc('%');  // 输出原样的'%'
                uart_putc(c);    // 输出未知的格式字符
                break;
        }
    }

    va_end(ap);  // 清理可变参数列表（必要的清理操作）
    return 0;    // 返回成功，符合C标准库规范
}

// 基础输出函数包装：提供更简洁的接口
void putc(char c) {
    uart_putc(c);  // 直接委托给UART驱动
}

void puts(const char *s) {
    uart_puts(s);  // 直接委托给UART驱动
}

// 清屏功能实现：使用ANSI转义序列控制终端
void clear_screen(void) {
    // ANSI转义序列格式：ESC[2J - 清除整个屏幕
    uart_putc(0x1B);  // ESC字符 (ASCII码27)
    uart_putc('[');   // 控制序列引导符
    uart_putc('2');   // 参数：2表示清除整个屏幕
    uart_putc('J');   // 命令：J表示清除显示操作
    
    // ANSI转义序列：ESC[H - 光标归位（移动到左上角）
    uart_putc(0x1B);  // ESC字符
    uart_putc('[');   // 控制序列引导符
    uart_putc('H');   // 命令：H表示光标定位（无参数时默认到左上角）
}

// 光标定位函数：移动光标到屏幕指定位置
// 参数：x - 列号(0-based), y - 行号(0-based)
void goto_xy(int x, int y) {
    // ANSI转义序列格式：ESC[row;colH
    uart_putc(0x1B);  // ESC字符
    uart_putc('[');   // 控制序列引导符
    
    // 输出行号（ANSI使用1-based索引，所以需要+1）
    int n = y + 1;
    if (n >= 10) {
        uart_putc('0' + n / 10);  // 输出十位数（如果有）
    }
    uart_putc('0' + n % 10);      // 输出个位数
    uart_putc(';');               // 行列分隔符
    
    // 输出列号（同样转换为1-based）
    n = x + 1;
    if (n >= 10) {
        uart_putc('0' + n / 10);  // 输出十位数（如果有）
    }
    uart_putc('0' + n % 10);      // 输出个位数
    uart_putc('H');               // 光标定位命令
}

// 清除当前行：从光标位置清除到行尾
void clear_line(void) {
    // ANSI转义序列：ESC[K - 清除从光标到行尾的内容
    uart_putc(0x1B);  // ESC字符
    uart_putc('[');   // 控制序列引导符
    uart_putc('K');   // 命令：K表示行清除操作
}

// 基础格式化测试函数：验证所有支持的格式符
void test_printf_basic(void) {
    puts("=== Basic Format Tests ===\n");
    
    // 测试各种格式符的正确性
    printf("Decimal: %d\n", 42);             // 十进制整数
    printf("Negative: %d\n", -123);          // 负整数
    printf("Unsigned: %u\n", 123);           // 无符号整数
    printf("Hexadecimal: 0x%x\n", 0xABC);    // 十六进制整数
    printf("Character: %c\n", 'X');          // 单个字符
    printf("String: %s\n", "Hello World");   // 字符串
    printf("Percent: %%\n");                 // 百分号字面量
}

// 边界情况测试函数：验证极端值和特殊情况处理
void test_printf_edge_cases(void) {
    puts("=== Edge Case Tests ===\n");
    
    // 测试各种边界情况
    printf("INT_MAX: %d\n", 2147483647);      // 32位有符号整数最大值
    printf("INT_MIN: %d\n", -2147483648);     // 32位有符号整数最小值
    printf("Zero: %d\n", 0);                  // 零值处理
    printf("NULL string: %s\n", (char*)0);    // 空指针安全性
    printf("Empty string: %s\n", "");         // 空字符串处理
    printf("Max hex: 0x%x\n", 0xFFFFFFFF);    // 最大32位十六进制值
}